"""
这是一个模拟空战多对多的环境，参照gym的交互逻辑设计，敌方目标随机生成于半径为150km的球内(已知歼11机载雷达的最大探测距离)，分辨率为1公里
"""

import copy
import math

import matplotlib.pyplot as plt
import numpy as np

import Env.AI_E.Enemy_Strategy as Ene_Str
import Env.Tools.ACFunc as ACF
import Env.Tools.ExcelFunc as exl
from Env.Entity.SAM import SAM
from Env.Entity.UAV import UAV
from Env.Entity.Missile_FIM import Missile
import multiprocessing as mp

Unit = {'UAV': UAV,
        'SAM': SAM}


class ACEnv():
    def __init__(self, n_friend, n_enemy,index=0,
                 Battle_range=40000, height=20, 初始生成距离=30000,
                 最大时间=500, type_e='SAM', type_f='UAV', 时间步长=1):
        self.action_space = range(72)  # 此处为所有初始步可能的动作
        self.Battle_range = Battle_range  # 战场平面范围 m
        self.height = height  # 高度限制 m
        # self.n_target=n_target  # 目标数目，暂时认为敌方既为目标
        self.type_e=type_e      # 地面实体目标，敌军类型
        self.n_enemy = n_enemy  # 敌军目标个数
        self.type_f=type_f      # 己方，友军类型
        self.n_friend = n_friend    # 友军目标个数
        self.duration = 最大时间  # 单位秒 一局的最大时长
        self.dt = 时间步长          # 每回合间隔时间
        self.rou = math.ceil(最大时间 / 时间步长)       # 返回数字的上入整数
        self.init_distance = 初始生成距离
        #self.exc = exl.excel()  # 构建记录文件
        self.Location_F_List = []  # 己方坐标列表，记录以往的所有坐标,结构为三层数组，第一层为回合，第二层为单位，第三层为坐标
        self.Location_E_List = []  # 敌方坐标列表，记录以往的所有坐标,结构同上
        self.index=index        # 实例序号

        """
        self.att_target = pd.DataFrame(np.zeros([n_friend,n_enemy],dtype=int),
                                     index=['第{}架友机'.format(str(i)) for i in range(1,(n_friend+1))],
                                     columns=['第{}个目标'.format(str(i)) for i in range(1,(n_enemy+1))])
        
        坐标位置放在每个实体中
        self.Location_F=pd.DataFrame(np.zeros([n_friend,3]),
                                     index=['第{}架友机'.format(str(i)) for i in range(1,(n_friend+1))],
                                     columns=list('XYZ'))   # 友机方位矩阵
        self.Location_E = pd.DataFrame(np.zeros([n_enemy, 3]),
                                       index=['第{}架敌机'.format(str(i)) for i in range(1, (n_enemy + 1))],
                                       columns=list('XYZ'))  # 敌机方位矩阵
        """

    def reset(self):    # TODO （zrc） 场景初始化，随机敌我双方出生点，返回
        self.enemies = self.objs_creat(self.n_enemy, self.type_e, 1)        # 单位类型数组（列表，列表中的元素是字典类型）
        self.friends = self.objs_creat(self.n_friend, self.type_f, 0)       # 单位类型数组
        self.att_target_f = [[[], [], [], []],
                             [[], [], [], []],
                             [[], [], [], []],
                             [[], [], [], []]]      # 新版记录，记录Missile实体
        #self.att_target_e = np.array([[-1] * self.n_enemy] * self.n_friend)  # 导弹命中倒计时e
        self.att_target_e = [[[], [], [], []],
                             [[], [], [], []],
                             [[], [], [], []],
                             [[], [], [], []]]      # 新版记录，记录Missile实体
        self.Location_F_List.clear()
        self.Location_E_List.clear()
        self.att_result = [[0] * self.n_enemy, [0] *self.n_friend]          # 攻击结果记录
        #self.exc.creat_sheet()
        self.build()        # 依据参数构建场景
        self.count_round=0          # 回合记录

        observation=self.get_observation()
        return observation

    # 单位创建,D_W为敌我识别,0是我方，1是对方
    def objs_creat(self, num, type, D_W):
        obj = []
        for i in range(0, num):
            name = 'FF' + str(i + 1) if D_W == 0 else 'DF'
            temp = Unit[type](name)    # 调用UAV或SAM的_init_（）方法，将一个UAV或SAM类型的对象赋值给temp
            obj.append(temp)
        return obj

    def build(self, View=1):  # 随机生成敌我双方位置,View为视角，1为以敌方为中心，0为以我方为中心
        mu1 = self.球面点随机(self.init_distance) if View == 1 else [0., 0., 0.]  # 己方坐标，传参初始距离
        mu2 = [0., 0., 0.] if View == 1 else self.球面点随机(self.init_distance)  # 敌方坐标
        for i in self.friends:
            i.Position = ((mu1 + np.random.uniform(-500, 500, [1, 3])) / 1000)[0]  # i是字典类型的列表的元素UAV或SAM，可以直接调用UAV的属性

        for j in self.enemies:
            ran = np.random.uniform(-5000, 5000, [1, 3])
            ran[0, 2] = 0.
            j.Position = ((mu2 + ran) / 1000)[0]

    def 球面点随机(self, distance):  # TODO (zrc) 在半球面上随机生成一个点，再转换成直角坐标系
        Theta = np.random.uniform(0, math.pi * 0.5)
        Phi = np.random.uniform(0, math.pi * 2)
        x = distance * math.sin(Theta) * math.cos(Phi)
        y = distance * math.sin(Theta) * math.sin(Phi)
        z = distance * math.cos(Theta)
        return [x, y, z]

    def get_observation(self):  # 得到observation!!!!!!!!!!!简化版环境
        observation = []

        Location_F = [f.Position for f in self.friends]  # 己方坐标
        Location_E = [e.Position for e in self.enemies]  # 敌方坐标
        P_destroied=[f.P_destroyed for f in self.friends]   # UAV被击中概率

        P = copy.deepcopy(Location_F)        # 避免直接传参为引用，使得列表列表数据不断重复，并出错
        self.Location_F_List.append(P)  # 将当前己方坐标加入到己方坐标列表中，以回合为单位
        self.Location_E_List.append(Location_E)  # 将当前敌方坐标加入到敌方坐标列表中

        observation.append(Location_F)  # 我方位置
        observation.append(Location_E)  # 敌方位置
        observation.append(P_destroied) # UAV被击中概率
        return observation

    def datacollect_mysql(self,ep,step,decisions):
        '''
        收集表中数据
        :param database:
        :param ep:
        :param step:
        :param decisions:
        :return:
        '''

        decision_1,decision_2,decision_3,decision_4,decision_5=decisions
        collections=[]
        count_uav,count_sam,count_missile_f,count_missile_e=0,0,0,0

        # UAV信息
        for uav in self.friends:
            #print(".P_destroyed",uav.P_destroyed)

            temp=[ep,step,'UAV',count_uav+1,float(uav.Position[0]),float(uav.Position[1]),float(uav.Position[2]),float(uav.pointing[0]),
                  float(uav.pointing[1]),float(uav.P_destroyed),-1,uav.live,-1,-1,uav.NumberOfMissile,-1,decision_1[count_uav],
                  decision_2[count_uav],decision_3[count_uav],decision_4[count_uav],decision_5[count_uav]]
            collections.append(temp)
            count_uav += 1
        # SAM信息
        for sam in self.enemies:

            temp=[ep,step,'SAM',count_sam+1,float(sam.Position[0]),float(sam.Position[1]),float(sam.Position[2]),-1,
                  -1,float(sam.P_destroyed),-1,sam.live,-1,-1,-1,sam.cool,-1,-1,-1,-1,-1]
            collections.append(temp)
            count_sam += 1


        for i in range(4):
            for j in range(4):
                for k in self.att_target_f[i][j]:
                    count_missile_f += 1
                    temp = [ep, step, 'Missile_F', count_missile_f, float(k.Position[0]), float(k.Position[1]), float(k.Position[2]), -1,
                            -1, -1, i, k.activity, k.命中结果, j, -1, -1, -1, -1, -1, -1, -1]
                    collections.append(temp)


        for i in range(4):
            for j in range(4):
                for k in self.att_target_e[i][j]:
                    count_missile_e += 1
                    temp = [ep, step, 'Missile_E', count_missile_e, float(k.Position[0]), float(k.Position[1]), float(k.Position[2]), -1,
                            -1, -1, i, k.activity, k.命中结果, j, -1, -1, -1, -1, -1, -1, -1]
                    collections.append(temp)

        return collections

    def attack_result(self):  # TODO （zrc）输入我方攻击列表和对方攻击列表，输出命中，未命中和差点命中
        # TODO （zrc）刷新状态,计算武器概率

        List_F = [f.Position for f in self.friends]
        for i in range(len(List_F), 4):
            List_F.append([0, 0, 0])
        Location_F = np.array(List_F)  # TODO (zrc) 将坐标补齐成4个,下同

        List_E = [e.Position for e in self.enemies]
        for i in range(len(List_E), 4):
            List_E.append([0, 0, 0])
        Location_E = np.array(List_E)

        Fire_para_F = ACF.utility(4, 4, Location_F, Location_E)
        Atta_Matrix_F = Fire_para_F.Run()  # 返回攻击概率矩阵
        Fire_para_E = ACF.utility(4, 4, Location_E, Location_F)
        Atta_Matrix_E = Fire_para_E.Run()  # 返回攻击概率矩阵
        count_matrix_f = np.zeros([4, 4])   # 存储导弹攻击生效的个数，即倒计时为0，活动标志为1的导弹
        count_matrix_e = np.zeros([4, 4])

        # 获得可以进行有效攻击的导弹个数矩阵
        for i in range(4):
            for j in range(4):
                count_matrix_f[i][j] = len([i for i in self.att_target_f[i][j] if i.activity == 1 and i.att_countdown==0])
                count_matrix_e[i][j] = len([i for i in self.att_target_e[i][j] if i.activity == 1 and i.att_countdown==0])
        Att_Result_F , P_Destroy_F= ACF.Attack.att_result(Atta_Matrix_F, count_matrix_f)  # 输入合成的攻击概率矩阵
        Att_Result_E , P_Destroy_E= ACF.Attack.att_result(Atta_Matrix_E, count_matrix_e)
        #print("P_Destroy_F:",P_Destroy_F)
        #print("P_Destroy_E:",P_Destroy_E)
        for e in self.enemies:
            e.P_destroyed = P_Destroy_F
        for f in self.friends:
            f.P_destroyed =  P_Destroy_E
        return [Att_Result_F, Att_Result_E]     # 返回攻击结果

    def do(self):  # 对环境进行更改，返回observation_和done
        done=True   # True意为未结束
        reward_done=0
        self.attack()

        livelist = [[f.live for f in self.friends], [e.live for e in self.enemies]]

        if (np.array(livelist[0])==0).all() :
            done=False
            # 如果wo方全灭，直接结算wo全部导弹,再计算回报
            for i in self.att_target_f:
                for j in i:
                    for m in j:
                        m.att_countdown=0
            self.attack()
            reward_done = self.reward()

        elif (np.array(livelist[1])==0).all():
            done = False
            # 如果di方全灭，直接结算di全部导弹,再计算回报
            for i in self.att_target_e:
                for j in i:
                    for m in j:
                        m.att_countdown=0
            self.attack()
            reward_done = self.reward()
        elif self.count_round>self.rou:
            done=False
            reward_done=self.reward()
        observation=self.get_observation()
        return observation,done,reward_done

    def attack(self):       # 推演攻击结果
        count_active_f = np.zeros([4, 4])  # 存储导弹攻击生效的个数，即倒计时为0，活动标志为1的导弹
        count_active_e = np.zeros([4, 4])
        for i in range(4):
            for j in range(4):
                count_active_f[i][j] = len([i for i in self.att_target_f[i][j]
                                            if i.activity == 1 and i.att_countdown == 0])
                count_active_e[i][j] = len([i for i in self.att_target_e[i][j]
                                            if i.activity == 1 and i.att_countdown == 0])
        if not ((count_active_f == np.array([[0] * 4] * 4)).all()
                and (count_active_e == np.array([[0] * 4] * 4)).all()):
            self.att_result = self.attack_result()  # TODO （zrc）根据结果处理成我方地方存活情况
            destroy_e = np.where(self.att_result[0] == 2)  # 敌方的被摧毁情况，返回的是一个攻击单位对其余所有未攻击过的单位的攻击结果矩阵，可以直接判断？？？？？
            destroy_f = np.where(self.att_result[1] == 2)  # 我方的被摧毁情况

            # 更新单位的存活状态和导弹的活动状态   TODO 修改了此处使UAV不会死
            # for i in destroy_f[1]:
            #     self.friends[i].live = 0
            #     for line in range(0, 4):
            #         for missle in self.att_target_e[line][i]:
            #             missle.activity = 0
            for j in destroy_e[1]:
                self.enemies[j].live = 0
                for line in range(0, 4):
                    for missle in self.att_target_f[line][j]:
                        missle.activity = 0
            self.flash_att_target()  # 攻击后修改DD状态

    def flash_att_target(self):
       for i in self.att_target_f:
           for j in i:
               for k in j:
                   if k.att_countdown==0:
                       k.activity=0

       for i in self.att_target_e:
           for j in i:
               for k in j:
                   if k.att_countdown==0:
                       k.activity=0


    # 参数schedule的含义攻击策略
    def FirstStep(self, schedule):  # TODO (zrc) 独立的第一步动作，确定在出生点时怎么进行*目标分配*，分配后直接拉到攻击边界
        Points_near = self.离散球面点穷举(20)  # 内球面，半径20
        Points_far = self.离散球面点穷举(22)  # 外球面，半径22

        for i in range(len(self.friends)):
            if schedule[i][1] < 60:
                pn=Points_near[schedule[i][1]]                  # 球面穷举的位置坐标，也为敌方的射程能够达到的（x,y,z）距离
                pe=self.enemies[schedule[i][0]].Position        # 敌方位置
                pf=pn+pe
                self.friends[i].Position = pf
                self.friends[i].pointing=[math.pi/2, math.atan2(-pn[1],-pn[0])]    # [俯仰角，偏转角]，要取反方向要在xy上加负号
            else:
                pn=Points_far[schedule[i][1] - 60]
                pe=self.enemies[schedule[i][0]].Position
                pf=pn+pe
                self.friends[i].Position = pf
                self.friends[i].pointing = [math.pi/2, math.atan2(-pn[1],-pn[0])]

        observation=self.get_observation()
        self.count_round+=1 # 回合记录
        return observation

    def 离散球面点穷举(self, r):
        points = []
        for i in range(1, 6):  # theta取值 15,30,45,60,75
            for j in range(12):  # phi取值0-360，步长30
                Theta = math.pi / 12 * i
                Phi = math.pi / 6 * j
                x = r * math.sin(Theta) * math.cos(Phi)
                y = r * math.sin(Theta) * math.sin(Phi)
                z = r * math.cos(Theta)
                points.append([x, y, z])
        return points

    def step(self, action):     # TODO (zrc) 第二阶段的动作，主要接受机动动作（俯仰角、偏转角）和攻击动作
        for uav in self.friends:
            uav.P_destroyed=0.

        eStrategy = Ene_Str.enemy_Strategy(self.n_enemy, self.n_friend, self.enemies, self.friends, self.dt)
        eStrategy_value = eStrategy.main()      # 获得地面单位的攻击策略

        self.count_round+=1 # 回合记录

        self.analy_location(action[0])  # 分析机动动作的影响
        self.analy_attack(action[1], 0)    # 分析攻击动作的影响,0为我方,1为AI
        self.analy_attack(eStrategy_value, 1)  # 分析攻击动作的影响,0为我方,1为AI
        observation_, done,reward_done = self.do()  # 进行动作仿真，得到observation_和done
        reward = self.reward_supervision(action[1])  # 计算回报值
        # if not done:
        #     self.exc.save()
        return observation_, reward+reward_done, done

    def analy_location(self,flight):  # 分析动作会对环境哪些方面产生影响，进行拆分
        a=0
        for i in self.friends:
            i.FlightTo(flight[a][0],flight[a][1],self.dt)
            a+=1

    # 一架无人机可以对多个目标进行攻击吗？（最多攻击两个）[0，1，0，1]    公式不太清楚？？？？？？？？？？
    def analy_attack(self,attack,D_W):  # TODO　（ｚｒｃ）　接收到的参数为[[0，1，0，1]...[...]]4*4的矩阵
        # 添加攻击动作
        a=-1
        for att in attack:
            a+=1
            if D_W == 0:    # 我方
                for i in range(len(att)):
                    if att[i] == 1 and self.friends[a].Attack(self.enemies[i].Position):
                        missile = Missile(self.count_round,0,self.friends[a].Position,self.enemies[i].Position)
                        self.att_target_f[a][i].append(missile)


            else:   # 敌方
                for i in range(len(att)):
                    if att[i] == 1 :
                        self.enemies[a].cd_reset()
                        missile=Missile(self.count_round,1,self.enemies[a].Position,self.friends[i].Position)
                        self.att_target_e[a][i].append(missile)

        #DD的动作：
        for i in range(4):
            for j in range(4):
                for k in self.att_target_f[i][j] :
                    if k.activity==1 and k.D_W==D_W:
                        k.fly(self.dt)
                for k in self.att_target_e[i][j] :
                    if k.activity==1 and k.D_W==D_W:
                        k.fly(self.dt)


    def reward(self):  # 1VS1的中止条件回报
        r=0
        if self.enemies[0].live==0:
            r=150 if self.friends[0].live==1 else 100
        else:
            r = 0 if self.friends[0].live == 1 else -50
        return r

    def reward_supervision(self,action):# 规则性回报，回报计算,飞出边界，瞎打弹惩罚等
        r=0
        if self.friends[0].Position[2]>self.height:     # 超出飞行上届-1
            r-=1
        if self.count_round>100:
            r-=1
        a=[]

        if len(action)>0 and self.friends[0].NumberOfMissile>0:
            if action[0][0]==1:
                r-=25
        return r

    def distance_xyz(self,A,B):
        x=B[0]-A[0]
        y = B[1] - A[1]
        z = B[2] - A[2]
        dis=math.sqrt(x**2+y**2+z**2)
        return dis

    # 去除坐标列表中的初始化坐标
    def move(self):
       self.Location_F_List.remove(self.Location_F_List[0])  # 去除坐标列表中初始化形成的坐标
       self.Location_E_List.remove(self.Location_E_List[0])  # 同上

    '''展示，绘制折线图'''
    def render(self,fig,ax):  # TODO (zrc) 展示当前敌我双方位置

        # figs = plt.figure()
        # ax = figs.add_subplot(111, projection='3d')  # 需要引入包from mpl_toolkits.mplot3d import axes3d，才能使用projection='3d'的取值
        ax.axis("equal")        # 有什么用？
        plt.grid(True)          # 网格
        plt.ion()               # 进入交互模式，不会结束对话，而是等待交流，继续加入代码，run后显示图像的改变

        if self.n_friend == 4:
            # 读取回合坐标
            Location_F_List = [Location_F for Location_F in self.Location_F_List] # 从己方坐标列表中读取每回合的各个单位的坐标
            Location_E = [e.Position for e in self.enemies]  # 敌方坐标
            pos = [[[],[],[]],[[],[],[]],[[],[],[]],[[],[],[]]]  # 用于存放读取出的坐标列表，第一层元素为0、1、2、3四个单位，第二层元素为x、y、z三个坐标

            # 读出己方坐标,Location_F是回合矩阵，friend是单位坐标矩阵
            for Location_F in Location_F_List:
                # 用于标记单位序号,不能放在下一个循环内
                i = 0

                for friend in Location_F:
                    pos[i][0].append(friend[0])
                    pos[i][1].append(friend[1])
                    pos[i][2].append(friend[2])
                    i += 1
            # 读取无人机的生存状态，用以绘图时区分无人机是否生存
            L1 = self.friends[0]
            L2 = self.friends[1]
            L3 = self.friends[2]
            L4 = self.friends[3]
            if L1.live == 1:
                line1, = ax.plot(pos[0][0], pos[0][1], pos[0][2], c='r', marker='*', ms=1)
            else:
                line1, = ax.plot(pos[0][0], pos[0][1], pos[0][2], c='#808080', marker='*', ms=1)
            if L2.live == 1:
                line2, = ax.plot(pos[1][0], pos[1][1], pos[1][2], c='b', marker='*', ms=1)
            else:
                line2, = ax.plot(pos[1][0], pos[1][1], pos[1][2], c='#808080', marker='*', ms=1)
            if L3.live == 1:
                line3, = ax.plot(pos[2][0], pos[2][1], pos[2][2], c='g', marker='*', ms=1)
            else:
                line3, = ax.plot(pos[2][0], pos[2][1], pos[2][2],c='#808080', marker='*', ms=1)
            if L4.live == 1:
                line4, = ax.plot(pos[3][0], pos[3][1], pos[3][2], c='c', marker='*', ms=1)
            else:
                line4, = ax.plot(pos[3][0], pos[3][1], pos[3][2], c='#808080', marker='*', ms=1)
            # 先存储，再通过读取进行绘制（画两个图例的办法）
            leg1 = plt.legend(loc='upper left', handles=[line1, line2, line3, line4], labels=['UAV1', 'UAV2', 'UAV3', 'UAV4'])

            # 遍历导弹实体，获取导弹实体记忆坐标,并绘制图像
            #空中单位发射
            for uav in self.att_target_f:
                for sam in uav:
                    for missile in sam:
                        pos_f_mis = [[], [], []]
                        for i in missile.position_memo:
                            pos_f_mis[0].append(i[0])
                            pos_f_mis[1].append(i[1])
                            pos_f_mis[2].append(i[2])
                        ax.plot(pos_f_mis[0], pos_f_mis[1], pos_f_mis[2], c='purple', linestyle=':', marker='*', ms=1)
            # 地面单位发射
            for sam in self.att_target_e:
                for uav in sam:
                    for missile in uav:
                        pos_e_mis = [[], [], []]
                        for i in missile.position_memo:
                            pos_e_mis[0].append(i[0])
                            pos_e_mis[1].append(i[1])
                            pos_e_mis[2].append(i[2])
                        ax.plot(pos_e_mis[0], pos_e_mis[1], pos_e_mis[2], c='black', linestyle=':', marker='*', ms=1)

            # self.att_target_e
            # 读取地面单位的坐标
            x_e_1 = Location_E[0][0]
            y_e_1 = Location_E[0][1]
            z_e_1 = Location_E[0][2]
            x_e_2 = Location_E[1][0]
            y_e_2 = Location_E[1][1]
            z_e_2 = Location_E[1][2]
            x_e_3 = Location_E[2][0]
            y_e_3 = Location_E[2][1]
            z_e_3 = Location_E[2][2]
            x_e_4 = Location_E[3][0]
            y_e_4 = Location_E[3][1]
            z_e_4 = Location_E[3][2]
            # 开始绘图
            # 对地面单位的存活状态进行判断，通过点的颜色区分地面单位是否存活
            if self.enemies[0].live == 1:
                P1 = ax.scatter3D(x_e_1, y_e_1, z_e_1, c='g', marker='D')
            else:
                P1 = ax.scatter3D(x_e_1, y_e_1, z_e_1, c='#3B3B3B', marker='*')
            if self.enemies[1].live == 1:
                P2 = ax.scatter3D(x_e_2, y_e_2, z_e_2, c='r', marker='D')
            else:
                P2 = ax.scatter3D(x_e_2, y_e_2, z_e_2, c='#3B3B3B', marker='*')
            if self.enemies[2].live == 1:
                P3 = ax.scatter3D(x_e_3, y_e_3, z_e_3, c='b', marker='D')
            else:
                P3 = ax.scatter3D(x_e_3, y_e_3, z_e_3, c='#3B3B3B', marker='*')
            if self.enemies[3].live == 1:
                P4 = ax.scatter3D(x_e_4, y_e_4, z_e_4, c='y', marker='D')
            else:
                P4 = ax.scatter3D(x_e_4, y_e_4, z_e_4, c='#3B3B3B', marker='*')
            plt.legend(loc='upper right', handles=[P1, P2, P3, P4],labels=['SAM1', 'SAM2', 'SAM3', 'SAM4'],scatterpoints=1)     # scatterpoints保证显示的是一个点
            plt.gca().add_artist(leg1)      # 绘制第一个图
            #ax.set_zlim3d(0, self.height)
            plt.pause(0)  # 图像更新显示更新的时间间隔

        elif self.n_friend == 1:

            # 读取回合坐标
            Location_F_List = [Location_F for Location_F in self.Location_F_List]  # 从己方坐标列表中读取每回合的各个单位的坐标
            Location_E = [e.Position for e in self.enemies]  # 敌方坐标
            pos = [[[], [], []]]  # 用于存放读取出的坐标列表，第一层元素为0、1、2、3四个单位，第二层元素为x、y、z三个坐标

            # 读出己方坐标,Location_F是回合矩阵，friend是单位坐标矩阵
            for Location_F in Location_F_List:
                i = 0  # 用于标记单位序号,不能放在下一个循环内
                for friend in Location_F:
                    pos[i][0].append(friend[0])
                    pos[i][1].append(friend[1])
                    pos[i][2].append(friend[2])
                    i += 1
            # print('开始仿真')
            L1 = self.friends[0]
            if L1.live == 1:
                line1, = ax.plot(pos[0][0], pos[0][1], pos[0][2], c='r', marker='*', ms=1)
            else:
                line1, = ax.plot(pos[0][0], pos[0][1], pos[0][2], c='#808080', marker='*', ms=1)
            leg1 = plt.legend(loc='upper left', handles=[line1],
                              labels=['UAV1'])  # 先存储，再通过读取进行绘制（画两个图例的办法）

            # 遍历导弹实体，获取导弹实体记忆坐标,并绘制图像
            # 空中单位发射
            for uav in self.att_target_f:
                for sam in uav:
                    for missile in sam:
                        pos_f_mis = [[], [], []]
                        for i in missile.position_memo:
                            # 有问题，不同的导弹轨迹连接到一起了。(原因是使用了同一个plot??????)
                            pos_f_mis[0].append(i[0])
                            pos_f_mis[1].append(i[1])
                            pos_f_mis[2].append(i[2])
                            # print('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%')
                            # print(pos_f_mis[0])
                        ax.plot(pos_f_mis[0], pos_f_mis[1], pos_f_mis[2], linestyle=':', c='purple', marker='*', ms=1)
            # 地面单位发射
            for sam in self.att_target_e:
                for uav in sam:
                    for missile in uav:
                        pos_e_mis = [[], [], []]
                        for i in missile.position_memo:
                            pos_e_mis[0].append(i[0])
                            pos_e_mis[1].append(i[1])
                            pos_e_mis[2].append(i[2])
                            # print('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%')
                            # print(pos_e_mis[0])
                        ax.plot(pos_e_mis[0], pos_e_mis[1], pos_e_mis[2], c='black', linestyle=':', marker='*', ms=1)




            # 读取地面单位的坐标
            x_e_1 = Location_E[0][0]
            y_e_1 = Location_E[0][1]
            z_e_1 = Location_E[0][2]
            # 开始绘图
            # 对地面单位的存活状态进行判断，通过点的颜色区分地面单位是否存活
            if self.enemies[0].live == 1:
                P1 = ax.scatter3D(x_e_1, y_e_1, z_e_1, c='g', marker='D')
            else:
                P1 = ax.scatter3D(x_e_1, y_e_1, z_e_1, c='#3B3B3B', marker='*')
            plt.legend(loc='upper right', handles=[P1], labels=['SAM1'],
                       scatterpoints=1)  # scatterpoints保证显示的是一个点
            plt.gca().add_artist(leg1)  # 绘制第一个图例
            #ax.set_zlim3d(0, self.height)
            plt.pause(0.01)  # 图像更新显示更新的时间间隔


        elif self.n_friend == 2:

            # 读取回合坐标
            Location_F_List = [Location_F for Location_F in self.Location_F_List]  # 从己方坐标列表中读取每回合的各个单位的坐标
            Location_E = [e.Position for e in self.enemies]  # 敌方坐标
            pos = [[[], [], []],[[],[],[]]]  # 用于存放读取出的坐标列表，第一层元素为0、1、2、3四个单位，第二层元素为x、y、z三个坐标

            # 读出己方坐标,Location_F是回合矩阵，friend是单位坐标矩阵
            for Location_F in Location_F_List:
                i = 0  # 用于标记单位序号,不能放在下一个循环内
                for friend in Location_F:
                    pos[i][0].append(friend[0])
                    pos[i][1].append(friend[1])
                    pos[i][2].append(friend[2])
                    i += 1
            # print('开始仿真')
            L1 = self.friends[0]
            L2=self.friends[1]
            if L1.live == 1:
                line1, = ax.plot(pos[0][0], pos[0][1], pos[0][2], c='r', marker='*', ms=1)
            else:
                line1, = ax.plot(pos[0][0], pos[0][1], pos[0][2], c='#808080', marker='*', ms=1)
            if L2.live == 1:
                line2, = ax.plot(pos[1][0], pos[1][1], pos[1][2], c='b', marker='*', ms=1)
            else:
                line2, = ax.plot(pos[1][0], pos[1][1], pos[1][2], c='#808080', marker='*', ms=1)
            leg1 = plt.legend(loc='upper left', handles=[line1,line2],
                              labels=['UAV1','UAV2'])  # 先存储，再通过读取进行绘制（画两个图例的办法）

            # 遍历导弹实体，获取导弹实体记忆坐标,并绘制图像
            # 空中单位发射
            for uav in self.att_target_f:
                for sam in uav:
                    for missile in sam:
                        pos_f_mis = [[], [], []]
                        for i in missile.position_memo:
                            # 有问题，不同的导弹轨迹连接到一起了。(原因是使用了同一个plot??????)
                            pos_f_mis[0].append(i[0])
                            pos_f_mis[1].append(i[1])
                            pos_f_mis[2].append(i[2])
                            # print('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%')
                            # print(pos_f_mis[0])
                        ax.plot(pos_f_mis[0], pos_f_mis[1], pos_f_mis[2], linestyle=':', c='purple', marker='*', ms=1)
            # 地面单位发射
            for sam in self.att_target_e:
                for uav in sam:
                    for missile in uav:
                        pos_e_mis = [[], [], []]
                        for i in missile.position_memo:
                            pos_e_mis[0].append(i[0])
                            pos_e_mis[1].append(i[1])
                            pos_e_mis[2].append(i[2])
                            # print('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%')
                            # print(pos_e_mis[0])
                        ax.plot(pos_e_mis[0], pos_e_mis[1], pos_e_mis[2], c='black', linestyle=':', marker='*', ms=1)




            # 读取地面单位的坐标
            x_e_1 = Location_E[0][0]
            y_e_1 = Location_E[0][1]
            z_e_1 = Location_E[0][2]
            # 开始绘图
            # 对地面单位的存活状态进行判断，通过点的颜色区分地面单位是否存活
            if self.enemies[0].live == 1:
                P1 = ax.scatter3D(x_e_1, y_e_1, z_e_1, c='g', marker='D')
            else:
                P1 = ax.scatter3D(x_e_1, y_e_1, z_e_1, c='#3B3B3B', marker='*')
            plt.legend(loc='upper right', handles=[P1], labels=['SAM1'],
                       scatterpoints=1)  # scatterpoints保证显示的是一个点
            plt.gca().add_artist(leg1)  # 绘制第一个图例
            #ax.set_zlim3d(0, self.height)
            plt.pause(0.01)  # 图像更新显示更新的时间间隔

    def distance(self,x1,x2,y1,y2,z1=0,z2=0):
        dis=math.sqrt((x2-x1)**2+(y2-y1)**2+(z2-z1)**2)
        return dis

    def excel_save(self):
        self.exc.save()


